import {
  WebSocketGateway,
  WebSocketServer,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from "@nestjs/websockets";
import { Injectable, Logger } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Server, WebSocket } from "ws";
import { URL } from "url";
import { UserService } from "../services/user.service";
import { CharacterService } from "../services/character.service";
import { RedisService } from "../services/redis.service";
import { ChatMessageService } from "../services/chat-message.service";
import { PrivateMessageService } from "../services/private-message.service";
import { AnnouncementService } from "../services/announcement.service";
import { ItemService } from "../services/item.service";
import { BasicItemService } from "../services/basic-item.service";
import { InventoryService } from "../services/inventory.service";
import { MonthlyCardService } from "../services/monthly-card.service";
import { CharacterSkillService } from "../services/character-skill.service";
import { KNOWN_WS_CODES } from "./known-ws-codes";
import { wsHandlers } from "./ws-handlers";
import { DeputyWsHandlers } from "./deputy-ws-handlers";
import { EquipmentWsHandlers } from "./equipment-ws-handlers";
import { inventoryWsHandlers } from "./inventory-ws-handlers";
import { factionWsHandlers } from "./faction-ws-handlers";
import { mountWsHandlers } from "./mount-ws-handlers";
import { ShopService } from "../services/shop.service";
import { DeputyGeneralService } from "../services/deputy-general.service";
import { FactionService } from "../services/faction.service";
import { CharacterMedicineService } from "../services/character-medicine.service";
import { CharacterEquipmentInventoryService } from "../services/character-equipment-inventory.service";
import { EquipmentBaseService } from "../services/equipment-base.service";
import { EquipmentGemSocketEntity } from "../entities/equipment-gem-socket.entity";
// 添加银行服务导入
import { BankService } from "../services/bank.service";
// 添加娱乐城相关服务导入
import { CasinoService } from "../modules/casino/casino.service";
import { parseFrontendBetType } from "../modules/casino/enums/bet-type-mapping.enum";
// 添加地图区域服务导入
import { MapAreaService } from "../services/map-area.service";
import { CharacterLocationService } from "../services/character-location.service";
import { NpcService } from "../services/npc.service";
import { MountBaseService } from "../services/mount-base.service";
import { CharacterMountService } from "../services/character-mount.service";
import { MountLevelExperienceService } from "../services/mount-level-experience.service";
import { TalentStoneService } from "../services/talent-stone.service";
import { TalentStoneWsHandlers } from "./talent-stone-ws-handlers";
import { TombWsHandlers } from "./tomb-ws-handlers";
import { HouseTrainingService } from "../services/house-training.service";
import { CharacterAttributeService } from "../services/character-attribute.service";
import { CharacterEquipmentService } from "../services/character-equipment.service";
import { PlayerOnlineTimeService } from "../services/player-online-time.service";
import { CharacterTrainingService } from "../services/character-training.service";
import { CharacterTrainingWsHandlers } from "./character-training-ws-handlers";
import { GemService } from "../services/gem.service";
import {
  ChibiBetData,
  CasinoBroadcastMessage,
} from "../modules/casino/interfaces/casino.interface";
import { UserAuthService } from "../services/user-auth.service";
import { SystemMessageService } from "../services/system-message.service";
import { DeputyAttributeService } from "../services/deputy-attribute.service";
import { VipService } from "../services/vip.service";
import { PlayerStatusService } from "../services/player-status.service";
import { StallService } from "../services/stall.service";
import { GoldTradeService } from "../services/gold-trade.service";

// 定义广播消息的类型接口
export interface BroadcastMessage {
  act_id: number;
  code: number;
  msg?: string;
  data?: any;
  [key: string]: any; // 允许其他字段
}

interface ClientMeta {
  userId: number;
  selectedCharacterId?: number; // 当前选择的角色ID
  roleName?: string; // 当前选择的角色名称
  token: string; // 添加token字段
  wsClientId?: string;
  areaSubscriptions?: Map<string, boolean>; // 记录客户端订阅的区消息频道
}

interface RoleInfo {
  allowLogin: number;
  headImg: string;
  id: number;
  lvl: number;
  name: string;
  roleType: number;
  sex: number;
}

@Injectable()
@WebSocketGateway({
  path: "/user-service/websocket",
  cors: { origin: true },
})
export class AppWsGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer()
  server!: Server;

  private readonly logger = new Logger("AppWsGateway");
  private readonly clientMeta = new WeakMap<WebSocket, ClientMeta>();
  private nextRoleId: number = 2000;

  constructor(
    private readonly userService: UserService,
    private readonly characterService: CharacterService,
    private readonly redisService: RedisService,
    private readonly chatMessageService: ChatMessageService,
    private readonly privateMessageService: PrivateMessageService,
    private readonly announcementService: AnnouncementService,
    private readonly itemService: ItemService,
    private readonly basicItemService: BasicItemService,
    private readonly inventoryService: InventoryService,
    private readonly monthlyCardService: MonthlyCardService,
    private readonly characterSkillService: CharacterSkillService,
    private readonly shopService: ShopService,
    private readonly deputyGeneralService: DeputyGeneralService,
    private readonly deputyAttributeService: DeputyAttributeService,
    private readonly vipService: VipService,
    private readonly factionService: FactionService,
    private readonly characterMedicineService: CharacterMedicineService,
    private readonly characterEquipmentInventoryService: CharacterEquipmentInventoryService,
    private readonly equipmentBaseService: EquipmentBaseService,
    private readonly deputyWsHandlers: DeputyWsHandlers,
    private readonly equipmentWsHandlers: EquipmentWsHandlers,
    // 添加银行服务
    private readonly bankService: BankService,
    // 添加娱乐城服务
    private readonly casinoService: CasinoService,
    // 添加地图区域服务
    private readonly mapAreaService: MapAreaService,
    // 添加位置服务
    private readonly characterLocationService: CharacterLocationService,
    // 添加NPC服务
    private readonly npcService: NpcService,
    // 添加坐骑服务
    private readonly mountBaseService: MountBaseService,
    private readonly characterMountService: CharacterMountService,
    private readonly mountLevelExperienceService: MountLevelExperienceService,
    private readonly talentStoneService: TalentStoneService,
    private readonly talentStoneWsHandlers: TalentStoneWsHandlers,
    private readonly characterTrainingService: CharacterTrainingService,
    private readonly characterTrainingWsHandlers: CharacterTrainingWsHandlers,
    private readonly gemService: GemService,
    private readonly userAuthService: UserAuthService,
    @InjectRepository(EquipmentGemSocketEntity)
    private readonly equipmentGemSocketRepository: Repository<EquipmentGemSocketEntity>,
    private readonly systemMessageService: SystemMessageService,
    private readonly characterAttributeService: CharacterAttributeService,
    private readonly characterEquipmentService: CharacterEquipmentService,
    private readonly playerOnlineTimeService: PlayerOnlineTimeService,
    private readonly tombWsHandlers: TombWsHandlers,
    private readonly stallService: StallService,
    private readonly playerStatusService: PlayerStatusService,
    private readonly houseTrainingService: HouseTrainingService,
    private readonly goldTradeService: GoldTradeService
  ) {}

  /**
   * 广播消息给所有连接的客户端
   */
  public broadcastToAll(payload: BroadcastMessage): void {
    try {
      if (this.server && this.server.clients) {
        let broadcastCount = 0;
        this.server.clients.forEach((client: WebSocket) => {
          if (client.readyState === WebSocket.OPEN) {
            try {
              client.send(JSON.stringify(payload));
              broadcastCount++;
            } catch (error: any) {
              this.logger.error(`广播消息失败: ${error?.message || error}`);
            }
          }
        });
        this.logger.log(`✅ 成功广播消息给 ${broadcastCount} 个客户端`);
      } else {
        this.logger.warn("WebSocket服务器未初始化，无法广播消息");
      }
    } catch (error: any) {
      this.logger.error(`广播消息异常: ${error?.message || error}`);
    }
  }

  /**
   * 广播消息给指定用户ID的客户端
   */
  public broadcastToUser(userId: number, payload: BroadcastMessage): void {
    try {
      if (this.server && this.server.clients) {
        let broadcastCount = 0;
        this.server.clients.forEach((client: WebSocket) => {
          const meta = this.clientMeta.get(client);
          if (
            meta &&
            meta.userId === userId &&
            client.readyState === WebSocket.OPEN
          ) {
            try {
              client.send(JSON.stringify(payload));
              broadcastCount++;
            } catch (error: any) {
              this.logger.error(
                `广播消息给用户 ${userId} 失败: ${error?.message || error}`
              );
            }
          }
        });
        if (broadcastCount > 0) {
          this.logger.log(`✅ 成功广播消息给用户 ${userId}`);
        }
      }
    } catch (error: any) {
      this.logger.error(
        `广播消息给用户 ${userId} 异常: ${error?.message || error}`
      );
    }
  }

  /** 踢出同一用户的其他连接（本进程） */
  private kickUserLocally(userId: number, reason: string): void {
    try {
      if (!this.server || !this.server.clients) return;
      this.server.clients.forEach((client: WebSocket) => {
        const meta = this.clientMeta.get(client);
        if (meta && meta.userId === userId) {
          try {
            if (client.readyState === WebSocket.OPEN) {
              client.send(
                JSON.stringify({
                  act_id: 9001,
                  code: 8,
                  msg: "您的账号在另一地点登录，您已下线",
                  data: { reason },
                })
              );
            }
          } catch {}
          try {
            client.close(4001, "kicked");
          } catch {}
        }
      });
    } catch (e) {
      this.logger.warn(`本地踢线失败 userId=${userId}: ${String(e)}`);
    }
  }

  /**
   * 广播消息给指定区服的所有在线玩家
   */
  public async broadcastToArea(
    areaId: number,
    payload: BroadcastMessage
  ): Promise<void> {
    try {
      // 使用Redis发布/订阅模式，发布区服消息
      const channelName = `area:${areaId}`;
      await this.redisService.publish(channelName, JSON.stringify(payload));

      this.logger.log(`✅ 区服消息已发布到Redis频道 ${channelName}`);
    } catch (error: any) {
      this.logger.error(`发布区服消息到Redis失败: ${error?.message || error}`);
    }
  }

  /**
   * 广播消息给指定帮派的所有在线成员
   */
  public async broadcastToFaction(
    factionId: number,
    payload: BroadcastMessage
  ): Promise<void> {
    try {
      // 使用Redis发布/订阅模式，发布帮派消息
      const channelName = `faction:${factionId}`;
      await this.redisService.publish(channelName, JSON.stringify(payload));

      this.logger.log(`✅ 帮派消息已发布到Redis频道 ${channelName}`);
    } catch (error: any) {
      this.logger.error(`发布帮派消息到Redis失败: ${error?.message || error}`);
    }
  }

  /**
   * 统一的发布消息方法
   * 根据消息体中的messageType参数自动选择发布频道
   */
  public async publishMessage(payload: BroadcastMessage): Promise<void> {
    try {
      const messageType = payload.data?.messageType;

      if (messageType === 1 && payload.data?.areaId) {
        // 区频道消息：发布到区服频道
        await this.broadcastToArea(payload.data.areaId, payload);
      } else if (messageType === 4 && payload.data?.factionId) {
        // 帮派频道消息：发布到帮派频道
        await this.broadcastToFaction(payload.data.factionId, payload);
      } else if (messageType === 5) {
        // 商屏消息：发布到全服频道
        await this.redisService.publish("global", JSON.stringify(payload));
        this.logger.log("✅ 商屏消息已发布到Redis全服频道");
      } else {
        this.logger.warn(
          `未知的消息类型或缺少必要参数: messageType=${messageType}`
        );
      }
    } catch (error: any) {
      this.logger.error(`发布消息失败: ${error?.message || error}`);
    }
  }

  /**
   * 订阅区消息频道（统一订阅所有类型的区消息）
   */
  public subscribeToAreaMessages(client: WebSocket): void {
    try {
      // 订阅区服频道（默认区服1）
      this.redisService.subscribe("area:1", (message: string) => {
        try {
          if (client.readyState === WebSocket.OPEN) {
            const payload = JSON.parse(message);
            console.log(" 订阅区服频道 现在发布到前端", payload);
            client.send(JSON.stringify(payload));
          }
        } catch (error: any) {
          this.logger.error(`处理区服消息失败: ${error?.message || error}`);
        }
      });

      // 订阅帮派频道（默认帮派1）
      this.redisService.subscribe("faction:1", (message: string) => {
        try {
          if (client.readyState === WebSocket.OPEN) {
            const payload = JSON.parse(message);
            client.send(JSON.stringify(payload));
          }
        } catch (error: any) {
          this.logger.error(`处理帮派消息失败: ${error?.message || error}`);
        }
      });

      // 订阅全服频道
      this.redisService.subscribe("global", (message: string) => {
        try {
          if (client.readyState === WebSocket.OPEN) {
            const payload = JSON.parse(message);
            client.send(JSON.stringify(payload));
          }
        } catch (error: any) {
          this.logger.error(`处理全服消息失败: ${error?.message || error}`);
        }
      });

      // 记录订阅信息到客户端元数据中
      const meta = this.clientMeta.get(client);
      if (meta) {
        meta.areaSubscriptions = new Map();
        meta.areaSubscriptions.set("area:1", true);
        meta.areaSubscriptions.set("faction:1", true);
        meta.areaSubscriptions.set("global", true);
      }

      this.logger.log(`✅ 客户端已订阅区消息频道 (区服1, 帮派1, 全服)`);
    } catch (error: any) {
      this.logger.error(`订阅区消息频道失败: ${error?.message || error}`);
    }
  }

  /**
   * 取消订阅区消息频道
   */
  public unsubscribeFromAreaMessages(client: WebSocket): void {
    try {
      const meta = this.clientMeta.get(client);
      if (meta?.areaSubscriptions) {
        meta.areaSubscriptions.clear();
        this.logger.log(`✅ 客户端已取消订阅所有区消息频道`);
      }
    } catch (error: any) {
      this.logger.error(`取消订阅区消息频道失败: ${error?.message || error}`);
    }
  }

  /**
   * 清理客户端的所有订阅
   */
  private cleanupClientSubscriptions(client: WebSocket): void {
    try {
      const meta = this.clientMeta.get(client);
      if (!meta) return;

      // 清理区消息订阅
      if (meta.areaSubscriptions) {
        meta.areaSubscriptions.clear();
      }

      this.logger.log(`✅ 客户端订阅已清理完成`);
    } catch (error: any) {
      this.logger.error(`清理客户端订阅失败: ${error?.message || error}`);
    }
  }

  /**
   * 获取角色名称（优先从Redis，备用从数据库）
   */
  private async getCharacterName(
    characterId: number,
    userId: number
  ): Promise<string> {
    try {
      // 首先尝试从Redis获取
      const userData = await this.redisService.get(`ws:user:${userId}`);
      if (userData) {
        const parsedData = JSON.parse(userData);
        if (parsedData.roleName) {
          return parsedData.roleName;
        }
      }

      // 如果Redis中没有，从数据库获取
      const character = await this.characterService.getCharacterById(
        characterId
      );
      if (character && character.name) {
        // 更新Redis缓存
        try {
          const currentUserData = await this.redisService.get(
            `ws:user:${userId}`
          );
          if (currentUserData) {
            const userDataObj = JSON.parse(currentUserData);
            userDataObj.roleName = character.name;
            await this.redisService.set(
              `ws:user:${userId}`,
              JSON.stringify(userDataObj)
            );
          }
        } catch (redisError) {
          this.logger.warn(`更新Redis角色名称失败: ${redisError}`);
        }
        return character.name;
      }

      // 如果都没有，返回默认值
      return "用户";
    } catch (error: any) {
      this.logger.warn(`获取角色名称失败: ${error?.message || error}`);
      return "用户";
    }
  }

  /**
   * 推送私信通知给指定角色ID的客户端
   */
  public pushPrivateMessageNotification(
    characterId: number,
    senderCharacterId: number,
    messageType: number = 1
  ): void {
    try {
      if (this.server && this.server.clients) {
        let pushCount = 0;
        this.server.clients.forEach((client: WebSocket) => {
          const meta = this.clientMeta.get(client);
          if (
            meta &&
            meta.selectedCharacterId === characterId &&
            client.readyState === WebSocket.OPEN
          ) {
            try {
              // 构建私信通知消息
              const notificationMessage = {
                act_id: 10,
                info_id: senderCharacterId || 1000,
                state: messageType, // 使用传入的消息类型
              };

              client.send(JSON.stringify(notificationMessage));
              pushCount++;

              this.logger.log(
                `✅ 私信通知推送成功: ${senderCharacterId} -> ${characterId}`
              );
            } catch (error: any) {
              this.logger.error(
                `推送私信通知给角色 ${characterId} 失败: ${
                  error?.message || error
                }`
              );
            }
          }
        });
        if (pushCount > 0) {
          this.logger.log(`✅ 成功推送私信通知给角色 ${characterId}`);
        } else {
          this.logger.log(
            `ℹ️ 角色 ${characterId} 当前不在线，无法推送私信通知`
          );
        }
      }
    } catch (error: any) {
      this.logger.error(
        `推送私信通知给角色 ${characterId} 异常: ${error?.message || error}`
      );
    }
  }

  /**
   * 检查用户是否有未读私信，如果有则推送通知
   */
  private async checkAndPushUnreadPrivateMessages(
    characterId: number,
    client: WebSocket
  ): Promise<void> {
    try {
      // 检查每个角色是否有未读私信
      const unreadCount = await this.privateMessageService.getUnreadCount(
        characterId
      );

      if (unreadCount > 0) {
        // 获取最近5条未读私信
        const unreadMessages =
          await this.privateMessageService.getRecentUnreadMessages(
            characterId,
            5
          );

        if (unreadMessages && unreadMessages.length > 0) {
          // 为每条未读私信推送通知
          for (const message of unreadMessages) {
            // messageType 和 state 含义一致，直接使用
            const state = message.messageType;

            // 推送私信通知
            const notificationMessage = {
              act_id: 10,
              info_id: message.senderCharacterId || 1000,
              state: state,
            };

            client.send(JSON.stringify(notificationMessage));
            this.logger.log(
              `✅ 推送未读私信通知: 角色${characterId} 收到来自${
                message.senderCharacterId
              }的${message.messageType === 2 ? "系统" : "玩家"}消息`
            );
          }

          this.logger.log(
            `✅ 共推送${unreadMessages.length}条未读私信通知给角色${characterId}`
          );
        }
      }
    } catch (error) {
      this.logger.error("检查未读私信失败:", error);
    }
  }

  /**
   * 检查用户是否有未读系统消息，如果有则推送通知
   */
  private async checkAndPushUnreadSystemMessages(
    characterId: number,
    client: WebSocket
  ): Promise<void> {
    try {
      // 检查用户是否有未读个人系统消息
      const unreadCount =
        await this.systemMessageService.getUnreadPersonalMessageCount(
          characterId
        );

      if (unreadCount > 0) {
        // 获取最近5条未读个人系统消息
        const unreadMessages =
          await this.systemMessageService.getUnreadPersonalMessages(
            characterId,
            5
          );

        if (unreadMessages && unreadMessages.length > 0) {
          // 为每条未读系统消息推送通知
          for (const message of unreadMessages) {
            // 推送系统消息通知
            const notificationMessage = {
              act_id: 10,
              info_id: message.senderId || 1000, // 使用消息的发送人ID，默认为1000（系统）
              state: 1, // 1表示系统消息类型
            };

            client.send(JSON.stringify(notificationMessage));
            this.logger.log(
              `✅ 推送未读系统消息通知: 角色${characterId} 收到来自${
                message.senderId || 1000
              }的系统消息ID${message.id}`
            );
          }

          this.logger.log(
            `✅ 共推送${unreadMessages.length}条未读系统消息通知给角色${characterId}`
          );
        }
      }
    } catch (error) {
      this.logger.error("检查未读系统消息失败:", error);
    }
  }

  async handleConnection(client: WebSocket, req: any): Promise<void> {
    try {
      const urlObj = new URL(req.url, `http://${req.headers.host}`);
      const token = urlObj.searchParams.get("t") || "";

      if (!token) {
        this.logger.warn("WebSocket连接失败：缺少token");
        client.close();
        return;
      }

      // 从token中解析用户信息，或者通过其他方式获取userId
      // 这里需要根据实际的token结构来实现
      const userData = await this.getUserIdFromToken(token);

      if (!userData) {
        this.logger.warn("WebSocket连接失败：无效token");
        client.close();
        return;
      }

      // 校验活跃会话（仅允许活跃token连接）
      const active = await this.userAuthService.getActiveSession(
        userData.userId
      );
      if (!active || active.token !== token) {
        this.logger.warn(`WS拒绝：非活跃会话 userId=${userData.userId}`);
        try {
          client.send(
            JSON.stringify({ act_id: 9001, code: 8, msg: "登录已失效" })
          );
        } catch {}
        client.close(4002, "inactive");
        return;
      }

      // 生成 wsClientId 并与活跃会话绑定
      const wsClientId = `ws_${Date.now()}_${Math.floor(Math.random() * 1e6)}`;
      await this.userAuthService.bindWsClientId(
        userData.userId,
        active.sessionId,
        wsClientId
      );

      // 同进程下，如果已有该用户连接，则踢下线
      this.kickUserLocally(userData.userId, "new_login");

      // 存储客户端元数据
      this.clientMeta.set(client, {
        userId: userData.userId,
        selectedCharacterId: userData.selectedCharacterId,
        token,
        roleName: userData.characterName,
        wsClientId,
        areaSubscriptions: new Map(), // 初始化区消息订阅
      });

      // 记录玩家登录在线时长
      if (userData.selectedCharacterId) {
        this.playerOnlineTimeService
          .recordLogin(userData.selectedCharacterId)
          .catch((err) =>
            this.logger.error(`记录玩家登录失败：${err.message}`)
          );
      }

      this.logger.log(`✅ WebSocket连接成功: userId=${userData.userId}`);

      // 验证token有效性
      if (!(await this.userService.validateToken(userData.userId, token))) {
        this.logger.warn(
          `WebSocket连接失败：token验证失败，userId=${userData.userId}`
        );
        client.close();
        return;
      }

      // 尝试从Redis恢复用户的角色选择状态
      let selectedCharacterId: number | undefined = undefined;
      try {
        const cached = await this.redisService.get(
          `user:selected_character:${userData.userId}`
        );
        if (cached) {
          const data = JSON.parse(cached);
          selectedCharacterId = data.characterId;
        }
      } catch (error) {
        this.logger.warn(
          `恢复用户角色选择状态失败，userId=${userData.userId}:`,
          error
        );
      }

      // // 设置客户端元数据
      this.clientMeta.set(client, {
        userId: userData.userId,
        selectedCharacterId, // 恢复的角色选择状态
        token,
        roleName: userData.characterName,
        areaSubscriptions: new Map(), // 初始化区消息订阅
      });

      // // 自动订阅区消息频道（包含区服、帮派、全服）
      this.subscribeToAreaMessages(client);

      // 订阅跨实例踢线事件
      try {
        await this.redisService.subscribe(
          "user:kick",
          async (message: string) => {
            try {
              const payload = JSON.parse(message);
              if (!payload || typeof payload.userId !== "number") return;
              // 防抖：仅当仍为当前活跃会话时执行
              const act = await this.userAuthService.getActiveSession(
                payload.userId
              );
              if (!act) return;
              this.kickUserLocally(payload.userId, payload.reason || "kick");
            } catch {}
          }
        );
      } catch {}

      // // 在Redis中记录用户连接状态
      await this.redisService.set(
        `ws:user:${userData.userId}`,
        JSON.stringify({
          characterId: selectedCharacterId, // 使用恢复的角色ID
          roleName: userData.characterName, // 添加角色名称
          connectedAt: Date.now(),
          token: token,
        }),
        3600 // 1小时过期
      );

      // // 如果有选中的角色，设置在线状态
      // if (selectedCharacterId) {
      //   try {
      //     if (this.characterLocationService) {
      //       await this.characterLocationService.setPlayerOnlineStatus(
      //         selectedCharacterId,
      //         true
      //       );
      //       this.logger.log(
      //         `✅ 玩家 ${selectedCharacterId} 连接时已设置为在线状态`
      //       );
      //     }
      //   } catch (error: any) {
      //     this.logger.error(`❌ 设置玩家在线状态失败: ${error?.message}`);
      //   }
      // }

      // this.logger.log(
      //   `WebSocket连接成功：userId=${userData.userId}（角色ID: ${
      //     selectedCharacterId || "未选择"
      //   }）`
      // );

      client.on("message", (raw: Buffer) => this.onMessage(client, raw));

      // 注意：300 消息推送延后到指令 5（选择/创建角色）后进行
    } catch (e) {
      this.logger.error("WebSocket连接处理异常:", e);
      client.close();
    }
  }

  async onModuleInit() {
    // 订阅娱乐城开奖消息
    await this.subscribeToCasinoEvents();
  }

  /**
   * 订阅娱乐城相关事件
   */
  private async subscribeToCasinoEvents(): Promise<void> {
    try {
      // 订阅大小玩法开奖结果
      await this.redisService.subscribe(
        "casino.dice.result",
        (message: string) => {
          try {
            const broadcastMessage: CasinoBroadcastMessage =
              JSON.parse(message);
            this.broadcastToAll(broadcastMessage);
            this.logger.log("✅ 收到大小玩法开奖消息，已广播给所有客户端");
          } catch (error) {
            this.logger.error("解析大小玩法开奖消息失败:", error);
          }
        }
      );

      // 订阅赤壁玩法开奖结果
      await this.redisService.subscribe(
        "casino.chibi.result",
        (message: string) => {
          try {
            const broadcastMessage: CasinoBroadcastMessage =
              JSON.parse(message);
            this.broadcastToAll(broadcastMessage);
            this.logger.log("✅ 收到赤壁玩法开奖消息，已广播给所有客户端");
          } catch (error) {
            this.logger.error("解析赤壁玩法开奖消息失败:", error);
          }
        }
      );

      // 订阅中奖通知
      await this.redisService.subscribe(
        "casino.winning.notification",
        async (message: string) => {
          try {
            const notification = JSON.parse(message);
            await this.handleCasinoWinningNotification(notification);
            this.logger.log("✅ 收到中奖通知消息，已处理");
          } catch (error) {
            this.logger.error("解析中奖通知消息失败:", error);
          }
        }
      );

      this.logger.log("🎰 娱乐城事件订阅成功");
    } catch (error) {
      this.logger.error("订阅娱乐城事件失败:", error);
    }
  }

  handleDisconnect(client: WebSocket): void {
    const meta = this.clientMeta.get(client);
    if (meta) {
      // 处理玩家下线，标记角色离线状态
      if (meta.selectedCharacterId) {
        this.markCharacterOffline(meta.selectedCharacterId, meta.userId).catch(
          (err) => this.logger.error(`标记角色离线失败：${err.message}`)
        );

        // 记录玩家离线在线时长
        this.playerOnlineTimeService
          .recordLogout(meta.selectedCharacterId)
          .catch((err) =>
            this.logger.error(`记录玩家离线失败：${err.message}`)
          );
      }

      // 清理Redis中的连接状态
      this.redisService
        .del(`ws:user:${meta.userId}`)
        .catch((err) =>
          this.logger.error(`清理Redis连接状态失败：${err.message}`)
        );
      this.clientMeta.delete(client);
      this.logger.log(`WebSocket断开连接：userId=${meta.userId}`);
    }
  }

  /**
   * 标记角色在线状态
   */
  private async markCharacterOnline(
    characterId: number,
    userId: number
  ): Promise<void> {
    try {
      // 在Redis中标记角色在线状态
      await this.redisService.set(
        `character:online:${characterId}`,
        JSON.stringify({
          onlineAt: Date.now(),
          userId: userId,
          status: "online",
        }),
        3600 // 1小时过期，需要定期刷新
      );

      // 添加到在线角色集合中
      await this.redisService.sadd("online_characters", characterId.toString());

      // 记录在线时间
      await this.redisService.set(
        `character:last_seen:${characterId}`,
        JSON.stringify({
          lastSeen: Date.now(),
          userId: userId,
        }),
        86400 // 24小时过期
      );

      this.logger.log(`✅ 角色 ${characterId} 已标记为在线状态`);
    } catch (error: any) {
      this.logger.error(`标记角色在线失败: ${error?.message || error}`);
    }
  }

  /**
   * 标记角色离线状态
   */
  private async markCharacterOffline(
    characterId: number,
    userId: number
  ): Promise<void> {
    try {
      // 从Redis中移除角色在线状态
      await this.redisService.del(`character:online:${characterId}`);

      // 从在线角色列表中移除
      await this.redisService.srem("online_characters", characterId.toString());

      // 记录离线时间 离线不用标记 非在线就是离线了
      // await this.redisService.set(
      //   `character:offline:${characterId}`,
      //   JSON.stringify({
      //     offlineAt: Date.now(),
      //     userId: userId
      //   }),
      //   86400 // 24小时过期
      // );

      this.logger.log(`✅ 角色 ${characterId} 已标记为离线状态`);
    } catch (error: any) {
      this.logger.error(`标记角色离线失败: ${error?.message || error}`);
    }
  }

  private send(client: WebSocket, payload: any): void {
    client.send(JSON.stringify(payload));
  }

  private async onMessage(client: WebSocket, raw: Buffer): Promise<void> {
    let msg: any;
    try {
      msg = JSON.parse(raw.toString());
    } catch (e) {
      return this.send(client, { code: -1, msg: "invalid json" });
    }

    const { d } = msg || {};
    const c: number = msg.c;
    const meta = this.clientMeta.get(client);

    if (!meta?.userId) {
      return this.send(client, {
        act_id: c,
        code: 401,
        msg: "用户未认证或连接已失效",
      });
    }

    const getBoundUserId = (): number => meta.userId;
    const getSelectedCharacterId = async (): Promise<number | undefined> => {
      try {
        const cached = await this.redisService.get(
          `user:selected_character:${meta.userId}`
        );
        if (cached) {
          const data = JSON.parse(cached);
          return data.characterId;
        }
      } catch (error: any) {
        this.logger.warn(`获取Redis中的角色选择状态失败：${error.message}`);
      }
      return meta.selectedCharacterId;
    };

    const getUserToken = async (uid: number): Promise<string> => {
      // 从Redis缓存中获取用户的token
      const userData = await this.redisService.get(`user:${uid}`);
      if (userData) {
        const parsed = JSON.parse(userData);
        return parsed.token || "";
      }
      return "";
    };

    const getUserRoles = async (uid: number): Promise<RoleInfo[]> => {
      try {
        const characters = await this.characterService.getUserCharacters(uid);
        return characters.map((char) => ({
          id: char.id,
          name: char.name,
          roleType: char.roleType,
          sex: char.sex,
          lvl: char.lvl,
          allowLogin: char.allowLogin,
          headImg: char.headImg || "",
        }));
      } catch (error: any) {
        this.logger.error(`获取用户角色失败：${error.message}`);
        return [];
      }
    };

    const updateSelectedCharacter = async (
      characterId: number,
      roleName: string
    ): Promise<void> => {
      meta.selectedCharacterId = characterId;
      meta.roleName = roleName;

      // 使用UserAuthService更新用户角色选择
      await this.userAuthService.updateUserCharacter(
        meta.userId,
        characterId,
        roleName
      );

      // 更新WebSocket用户数据中的角色信息
      try {
        await this.redisService.set(
          `ws:user:${meta.userId}`,
          JSON.stringify({
            characterId: characterId,
            roleName: roleName,
            connectedAt: Date.now(),
            token: meta.token,
          }),
          3600 // 1小时过期
        );
      } catch (error: any) {
        this.logger.error(`❌ 更新WebSocket用户数据失败: ${error?.message}`);
      }

      // 标记角色在线状态到Redis
      try {
        await this.markCharacterOnline(characterId, meta.userId);
      } catch (error: any) {
        this.logger.error(`❌ 标记角色在线状态失败: ${error?.message}`);
      }

      // 设置玩家在线状态并同步到Redis
      try {
        if (this.characterLocationService) {
          await this.characterLocationService.setPlayerOnlineStatus(
            characterId,
            true
          );
          this.logger.log(`✅ 玩家 ${characterId} 已设置为在线状态`);
        }
      } catch (error: any) {
        this.logger.error(`❌ 设置玩家在线状态失败: ${error?.message}`);
      }

      // 记录在线时长登录点（确保角色选择后一定产生当天记录）
      try {
        await this.playerOnlineTimeService.recordLogin(characterId);
      } catch (error: any) {
        this.logger.warn(
          `记录在线时长登录失败: characterId=${characterId}, ${error?.message}`
        );
      }

      // 角色选择成功后，主动发送位置信息
      await this.sendMyLoginHomeInfo(client, characterId);
    };

    switch (c) {
      // 娱乐城相关指令处理
      // 大小玩法接口
      case 1332: // 查询大小押注信息
        try {
          const result = await this.casinoService.getDiceGameInfo();
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理大小玩法信息查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 1332,
            code: -1,
            msg: error?.message || "获取大小玩法信息失败",
          });
        }

      case 1451: // 查询当前玩家金币
        try {
          // 优先使用选中的角色ID，如果没有则使用用户ID
          const characterId = meta.selectedCharacterId || meta.userId;
          const result = await this.characterService.getPlayerGold(characterId);
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理玩家金币查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 1451,
            code: -1,
            msg: error?.message || "获取玩家金币失败",
          });
        }

      case 1336: // 大小玩法下注
        try {
          // 使用统一的枚举系统解析前端下注类型和货币类型
          const { betType, currencyType } = parseFrontendBetType(d.type);

          // 转换标准请求格式为接口期望格式
          const betData = {
            userId: meta.userId,
            characterId: meta.selectedCharacterId || 0,
            betType: betType,
            betAmount: d.bet, // bet 对应下注金额
            currencyType: currencyType,
          };

          const result = await this.casinoService.placeDiceBet(
            meta.selectedCharacterId || 0,
            betData
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理大小玩法下注失败：${error?.message}`);
          return this.send(client, {
            act_id: 1336,
            code: 8,
            msg: error?.message || "大小玩法下注失败",
          });
        }

      case 1338: // 查看大小开奖历史记录
        try {
          const page = d?.pageNum || 0;
          const result = await this.casinoService.getDiceHistory(page);
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理大小玩法历史查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 1338,
            code: -1,
            msg: error?.message || "获取大小玩法历史失败",
          });
        }

      case 1339: // 查看大小我的投注记录
        try {
          const pageNum = d?.pageNum || 0; // 标准格式：pageNum从0开始
          const result = await this.casinoService.getDiceMyBets(
            meta.selectedCharacterId || 0,
            pageNum
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(
            `处理大小玩法我的投注记录查询失败：${error?.message}`
          );
          return this.send(client, {
            act_id: 1339,
            code: -1,
            msg: error?.message || "获取我的大小玩法下注失败",
          });
        }

      // 赤壁玩法接口
      case 4437: // 下注支援
        try {
          // 字段映射：将前端的side、type、bet字段映射到ChibiBetData接口
          const { side, type, bet } = d;

          // 验证必需字段
          if (!side || !type || !bet) {
            return this.send(client, {
              act_id: 4430,
              code: -1,
              msg: "缺少必需的下注参数",
            });
          }

          // 构建下注数据对象，字段与casino.service.ts中的期望一致
          const betData = {
            characterId: meta.selectedCharacterId || 0,
            side: parseInt(side), // side: 1=魏, 2=蜀, 3=吴
            type: type, // type: "1"=金币, "2"=银币
            bet: parseInt(bet), // 下注金额
          };

          const result = await this.casinoService.placeChibiBet(
            meta.selectedCharacterId || 0,
            betData
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理赤壁玩法下注失败：${error?.message}`);
          return this.send(client, {
            act_id: 4437,
            code: 8,
            msg: error?.message || "赤壁玩法下注失败",
          });
        }

      case 4430: // 赤壁动态查询 - 返回历史记录
        try {
          const page = d?.pageNum || 0;
          const result = await this.casinoService.getChibiHistoryFor4430(page);
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理赤壁历史记录查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 4430,
            code: -1,
            msg: error?.message || "获取赤壁历史记录失败",
          });
        }

      case 5281: // 赤壁中奖名单
        try {
          const page = d?.pageNum || 0;
          const result = await this.casinoService.getChibiWinners(page);
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理赤壁中奖名单查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 5281,
            code: -1,
            msg: error?.message || "获取赤壁中奖名单失败",
          });
        }

      case 4434: // 赤壁历史记录
        try {
          const page = d?.pageNum || 0;
          const result = await this.casinoService.getChibiHistory(page);
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理赤壁玩法历史查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 4434,
            code: -1,
            msg: error?.message || "获取赤壁玩法历史失败",
          });
        }

      case 4435: // 赤壁我的支援记录
        try {
          const page = d?.pageNum || 0;

          // 使用角色ID而不是用户ID来查询
          const characterId = meta.selectedCharacterId || meta.userId;

          const result = await this.casinoService.getChibiMyBets(
            characterId,
            page
          );

          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理赤壁我的支援记录查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 4435,
            code: -1,
            msg: error?.message || "获取赤壁我的支援记录失败",
          });
        }

      // 猜拳玩法接口
      case 2110: // 发起猜拳挑战
        try {
          // 从Redis中获取用户的角色名称
          let roleName = "挑战者"; // 默认值
          try {
            const userData = await this.redisService.get(
              `ws:user:${meta.userId}`
            );
            if (userData) {
              const parsedData = JSON.parse(userData);
              roleName = parsedData.roleName || "挑战者";
            }
          } catch (redisError) {
            this.logger.warn(`从Redis获取角色名称失败: ${redisError}`);
          }

          if (!roleName) {
            roleName = await this.getCharacterName(
              meta.selectedCharacterId || 0,
              meta.userId
            );
          }

          // 将roleName添加到挑战数据中
          const challengeDataWithRoleName = {
            ...d,
            challengerName: roleName,
          };

          const result = await this.casinoService.createRockPaperScissors(
            meta.selectedCharacterId || 0,
            challengeDataWithRoleName
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理猜拳挑战发起失败：${error?.message}`);
          return this.send(client, {
            act_id: 2110,
            code: -1,
            msg: error?.message || "发起猜拳挑战失败",
          });
        }

      case 2103: // 获取猜拳挑战列表
        try {
          const page = d?.pageNum || 0;
          const result = await this.casinoService.getRPSChallenges(page);
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理猜拳挑战列表查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 2103,
            code: -1,
            msg: error?.message || "获取猜拳挑战列表失败",
          });
        }

      case 2111: // 应战猜拳
        try {
          // 从Redis中获取用户的角色名称
          let roleName = "用户"; // 默认值
          try {
            const userData = await this.redisService.get(
              `ws:user:${meta.userId}`
            );
            if (userData) {
              const parsedData = JSON.parse(userData);
              roleName = parsedData.roleName || "用户";
            }
          } catch (redisError) {
            this.logger.warn(`从Redis获取角色名称失败: ${redisError}`);
          }

          if (!roleName) {
            roleName = await this.getCharacterName(
              meta.selectedCharacterId || 0,
              meta.userId
            );
          }

          // 兼容标准文档与历史格式：{ id, value } 或 { challengeId, response }
          const payload: {
            id?: number | string;
            challengeId?: number | string;
            value?: number | string;
            response?: number | string;
          } = d || {};
          const challengeId = payload.challengeId ?? payload.id;
          const response = payload.response ?? payload.value;
          if (!challengeId) {
            throw new Error("挑战ID不能为空");
          }
          if (response === undefined || response === null) {
            throw new Error("响应不能为空");
          }

          // 创建包含角色名称的响应数据
          const responseData = {
            challengeId: Number(challengeId),
            responderId: meta.selectedCharacterId || 0,
            responderName: roleName,
            responderValue: Number(response),
          };

          const result = await this.casinoService.respondToChallenge(
            meta.selectedCharacterId || 0,
            Number(challengeId),
            responseData
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理猜拳应战失败：${error?.message}`);
          return this.send(client, {
            act_id: 2111,
            code: -1,
            msg: error?.message || "应战猜拳失败",
          });
        }

      case 2105: // 获取猜拳挑战记录
        try {
          const page = d?.pageNum || 0;
          const result = await this.casinoService.getRPSChallengeRecords(
            meta.userId,
            page
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理猜拳挑战记录查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 2105,
            code: -1,
            msg: error?.message || "获取猜拳挑战记录失败",
          });
        }

      case 2106: // 获取猜拳响应记录
        try {
          const page = d?.pageNum || 0;
          const result = await this.casinoService.getRPSResponseRecords(
            meta.userId,
            page
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理猜拳响应记录查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 2106,
            code: -1,
            msg: error?.message || "获取猜拳响应记录失败",
          });
        }

      case 2108: // 获取猜拳胜率排行榜
        try {
          const page = d?.pageNum || 0;
          const result = await this.casinoService.getRPSWinRankings(page);
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理猜拳胜率排行榜查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 2108,
            code: -1,
            msg: error?.message || "获取猜拳胜率排行榜失败",
          });
        }

      case 2109: // 获取猜拳盈利排行榜
        try {
          const page = d?.pageNum || 0;
          const result = await this.casinoService.getRPSProfitRankings(page);
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理猜拳盈利排行榜查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 2109,
            code: -1,
            msg: error?.message || "获取猜拳盈利排行榜失败",
          });
        }

      // 副将系统相关指令处理
      case 1009: // 查看副将详情
        try {
          const result = await this.deputyWsHandlers.handleDeputyDetail(
            d,
            meta.selectedCharacterId || 0
          );
          return this.send(client, result);
        } catch (error: any) {
          return this.send(client, {
            act_id: 1009,
            code: -1,
            msg: error?.message || "处理失败",
          });
        }

      case 1110: // 查询副将属性信息
        try {
          const result = await this.deputyWsHandlers.handleDeputyAttributes(
            d,
            meta.selectedCharacterId || 0
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将属性查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 1110,
            code: -1,
            msg: error?.message || "查询副将属性失败",
          });
        }

      case 1119: // 查看副将列表
        try {
          const result = await this.deputyWsHandlers.handleDeputyList(
            d,
            meta.selectedCharacterId || 0
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将列表查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 1119,
            code: -1,
            msg: error?.message || "获取副将列表失败",
          });
        }

      // 查询可用副将列表（根据物品gid）
      case 2015:
        try {
          const gid = d?.gid;
          const pageNum = d?.pageNum || 0;
          const selectedCharacterId = meta.selectedCharacterId || 0;
          const res = await this.deputyGeneralService.getDeputyMindEligibleList(
            Number(selectedCharacterId),
            Number(gid),
            Number(pageNum)
          );
          return this.send(client, {
            act_id: 2015,
            code: 0,
            list: res.list,
            page: 1,
            sum: res.sum,
          });
        } catch (error: any) {
          return this.send(client, {
            act_id: 2015,
            code: 8,
            msg: error?.message || "您没有这个物品",
          });
        }

      // 2029：与2015相同，查询当前心法可用的副将列表
      case 2029:
        try {
          const gid = d?.gid;
          const pageNum = d?.pageNum || 0;
          const selectedCharacterId = meta.selectedCharacterId || 0;
          const res = await this.deputyGeneralService.getDeputyMindEligibleList(
            Number(selectedCharacterId),
            Number(gid),
            Number(pageNum)
          );
          return this.send(client, {
            act_id: 2029,
            code: 0,
            list: res.list,
            page: 1,
            sum: res.sum,
          });
        } catch (error: any) {
          return this.send(client, {
            act_id: 2029,
            code: 8,
            msg: error?.message || "您没有这个物品",
          });
        }

      // 使用副将经验书（+5000）
      case 2016:
        try {
          const gid = d?.gid; // 83
          const cid = d?.cid; // player_deputy.id
          const selectedCharacterId = meta.selectedCharacterId || 0;
          const res = await this.deputyGeneralService.useDeputyExpBook(
            Number(selectedCharacterId),
            Number(gid),
            Number(cid)
          );
          const msg = `副将增加经验值 ${res.expGained}${
            res.levelUpTimes > 0 ? ",级别提升 " + res.levelUpTimes + " 级" : ""
          }`;
          return this.send(client, { act_id: 2016, code: 0, msg });
        } catch (error: any) {
          return this.send(client, {
            act_id: 2016,
            code: -1,
            msg: error?.message || "使用失败",
          });
        }

      case 1122: // 洗副将属性
        try {
          const result = await this.deputyWsHandlers.handleWashDeputyAttribute(
            d,
            meta.selectedCharacterId || 0
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理洗副将属性失败：${error?.message}`);
          return this.send(client, {
            act_id: 1122,
            code: -1,
            msg: error?.message || "洗副将属性失败",
          });
        }

      case 2072: // 副将上阵/下阵/位置交换操作
        try {
          const result =
            await this.deputyWsHandlers.handleDeputyBattleOperation(
              d,
              meta.selectedCharacterId || 0
            );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将操作失败：${error?.message}`);
          return this.send(client, {
            act_id: 2072,
            code: -1,
            msg: error?.message || "副将操作失败",
          });
        }

      case 1419: // 查看副将列表（包括可以放到仓库的副将和仓库中的副将）
        try {
          const result = await this.deputyWsHandlers.handleDeputyWarehouseList(
            d,
            meta.selectedCharacterId || 0
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将仓库列表失败：${error?.message}`);
          return this.send(client, {
            act_id: 1419,
            code: -1,
            msg: error?.message || "获取副将列表失败",
            list: [],
            sum: 0,
            type: 0,
          });
        }

      case 1420: // 副将仓库操作（存储到仓库和从仓库提取）
        try {
          const result =
            await this.deputyWsHandlers.handleDeputyWarehouseOperation(
              d,
              meta.selectedCharacterId || 0
            );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将仓库操作失败：${error?.message}`);
          return this.send(client, {
            act_id: 1420,
            code: -1,
            msg: error?.message || "副将仓库操作失败",
          });
        }

      case 1131: // 副将使用技能
        try {
          const result = await this.deputyWsHandlers.handleDeputyUseSkill(
            d,
            meta.userId
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将使用技能失败：${error?.message}`);
          return this.send(client, {
            act_id: 1131,
            code: -1,
            msg: error?.message || "副将使用技能失败",
          });
        }

      case 1194: // 获取副将等级榜排名
        try {
          const result = await this.deputyWsHandlers.handleDeputyLevelRanking(
            d,
            meta.selectedCharacterId || 0
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将等级榜查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 1194,
            code: -1,
            msg: error?.message || "获取副将等级榜失败",
            list: [],
            page: 1,
            sum: 0,
          });
        }

      case 1132: // 副将技能升级
        try {
          const result = await this.deputyWsHandlers.handleDeputySkillUpgrade(
            d,
            meta.userId
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将技能升级失败：${error?.message}`);
          return this.send(client, {
            act_id: 1132,
            code: -1,
            msg: error?.message || "副将技能升级失败",
          });
        }

      case 8714: // 副将学习技能
        try {
          const result = await this.deputyWsHandlers.handleDeputyLearnSkill(
            d,
            meta.userId
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将学习技能失败：${error?.message}`);
          return this.send(client, {
            act_id: 8714,
            code: -1,
            msg: error?.message || "副将学习技能失败",
          });
        }

      case 1396: // 副将学习/重修技能
        try {
          const result = await this.deputyWsHandlers.handleDeputyLearnOrRelearn(
            d,
            meta.selectedCharacterId || 0
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理1396失败：${error?.message}`);
          return this.send(client, {
            act_id: 1396,
            code: 8,
            msg: error?.message || "处理失败",
          });
        }

      case 8718: // 副将默契培养
        try {
          const result = await this.deputyWsHandlers.handleDeputyMqdCultivation(
            d,
            meta.userId
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将默契培养失败：${error?.message}`);
          return this.send(client, {
            act_id: 8718,
            code: -1,
            msg: error?.message || "副将默契培养失败",
          });
        }

      case 8765: // 副将生成
        try {
          const result = await this.deputyWsHandlers.handleDeputyGeneration(
            d,
            meta.userId
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理副将生成失败：${error?.message}`);
          return this.send(client, {
            act_id: 8765,
            code: -1,
            msg: error?.message || "副将生成失败",
          });
        }

      // 装备系统相关指令处理
      case 1301: // 装备商店列表查询
        try {
          const result = await this.equipmentWsHandlers.handleEquipmentShopList(
            d
          );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理装备商店列表查询失败：${error?.message}`);
          return this.send(client, {
            act_id: 1301,
            code: -1,
            msg: error?.message || "查询装备商店列表失败",
          });
        }

      case 1302: // 银币购买装备
        try {
          const result =
            await this.equipmentWsHandlers.handlePurchaseEquipmentWithSilver(
              d,
              {
                selectedCharacterId: meta.selectedCharacterId,
                shopService: this.shopService,
                characterEquipmentInventoryService:
                  this.characterEquipmentInventoryService,
              }
            );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理银币购买装备失败：${error?.message}`);
          return this.send(client, {
            act_id: 1302,
            code: -1,
            msg: error?.message || "购买装备失败",
          });
        }

      // 背包物品使用相关指令处理
      case 1387: // 物品使用指令
        try {
          if (inventoryWsHandlers[1387]) {
            const result = await inventoryWsHandlers[1387](d, {
              userId: getBoundUserId(),
              selectedCharacterId: await getSelectedCharacterId(),
              deputyGeneralService: this.deputyGeneralService,
              inventoryService: this.inventoryService,
              characterService: this.characterService,
              systemMessageService: this.systemMessageService,
              pushMessage: async (message: any) => {
                if (message && message.act_id === 10) {
                  if (!message.info_id || message.info_id === 0) {
                    message.info_id = 1000;
                  }
                }
                this.send(client, message);
              },
            });
            return this.send(client, result);
          }
        } catch (error: any) {
          this.logger.error(`处理物品使用失败：${error?.message}`);
          return this.send(client, {
            act_id: 1387,
            code: -1,
            msg: error?.message || "物品使用失败",
          });
        }

      case 1056: // 查询玩家当前部位可佩戴装备列表
        try {
          if (inventoryWsHandlers[1056]) {
            const result = await inventoryWsHandlers[1056](d, {
              userId: getBoundUserId(),
              selectedCharacterId: await getSelectedCharacterId(),
              deputyGeneralService: this.deputyGeneralService,
              inventoryService: this.inventoryService,
              characterService: this.characterService,
              systemMessageService: this.systemMessageService,
              characterEquipmentInventoryService:
                this.characterEquipmentInventoryService,
              equipmentGemSocketRepository: this.equipmentGemSocketRepository,
              pushMessage: async (message: any) => {
                if (message && message.act_id === 10) {
                  if (!message.info_id || message.info_id === 0) {
                    message.info_id = 1000;
                  }
                }
                this.send(client, message);
              },
            });
            return this.send(client, result);
          }
        } catch (error: any) {
          this.logger.error(`处理可佩戴装备列表失败：${error?.message}`);
          return this.send(client, {
            act_id: 1056,
            code: -1,
            msg: error?.message || "查询失败",
          });
        }
        break;

      case 1062: // 装备详情查看指令
        try {
          if (inventoryWsHandlers[1062]) {
            const result = await inventoryWsHandlers[1062](d, {
              userId: getBoundUserId(),
              selectedCharacterId: await getSelectedCharacterId(),
              deputyGeneralService: this.deputyGeneralService,
              inventoryService: this.inventoryService,
              characterService: this.characterService,
              systemMessageService: this.systemMessageService,
              characterEquipmentInventoryService:
                this.characterEquipmentInventoryService,
              equipmentGemSocketRepository: this.equipmentGemSocketRepository,
              pushMessage: async (message: any) => {
                if (message && message.act_id === 10) {
                  if (!message.info_id || message.info_id === 0) {
                    message.info_id = 1000;
                  }
                }
                this.send(client, message);
              },
            });
            return this.send(client, result);
          }
        } catch (error: any) {
          this.logger.error(`处理装备详情查看失败：${error?.message}`);
          return this.send(client, {
            act_id: 1062,
            code: -1,
            msg: error?.message || "获取装备详情失败",
          });
        }
        break;

      // 天赋石系统相关指令处理
      case 6035: // 获取天赋石列表
      case 6184: // 查看天赋石详情
      case 6186: // 天赋石操作（激活、升级、装备、卸下）
      case 6185: // 吸收天赋石
      case 6189: // 获取可吸收的天赋石列表
      case 6188: // 获取已装备的天赋石列表
      case 6187: // 副将天赋石操作
        try {
          const result =
            await this.talentStoneWsHandlers.handleTalentStoneCommand(
              c,
              d,
              meta.selectedCharacterId || 0
            );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理天赋石指令 ${c} 失败:`, error);
          return this.send(client, {
            act_id: c,
            code: -1,
            msg: error?.message || "处理失败",
          });
        }

      // 主将训练系统相关指令处理
      case 1204: // 获取训练信息
      case 1205: // 获取训练详情
      case 1207: // 开始训练
      case 1208: // 领取训练奖励
        try {
          const result =
            await this.characterTrainingWsHandlers.handleCharacterTrainingCommand(
              c,
              d,
              {
                userId: getBoundUserId(),
                selectedCharacterId: await getSelectedCharacterId(),
                getUserToken: async (uid: number) => getUserToken(uid),
                getUserRoles: async (uid: number) => getUserRoles(uid),
                updateSelectedCharacter: async (
                  characterId: number,
                  roleName: string
                ) => updateSelectedCharacter(characterId, roleName),
                newRoleId: () => this.nextRoleId++,
                characterService: this.characterService,
                redisService: this.redisService,
                chatMessageService: this.chatMessageService,
                privateMessageService: this.privateMessageService,
                announcementService: this.announcementService,
                itemService: this.itemService,
                basicItemService: this.basicItemService,
                inventoryService: this.inventoryService,
                characterMedicineService: this.characterMedicineService,
                characterEquipmentInventoryService:
                  this.characterEquipmentInventoryService,
                equipmentBaseService: this.equipmentBaseService,
                monthlyCardService: this.monthlyCardService,
                characterSkillService: this.characterSkillService,
                shopService: this.shopService,
                deputyGeneralService: this.deputyGeneralService,
                bankService: this.bankService,
                casinoService: this.casinoService,
                mapAreaService: this.mapAreaService,
                locationService: this.characterLocationService,
                npcService: this.npcService,
                mountBaseService: this.mountBaseService,
                characterMountService: this.characterMountService,
                mountLevelExperienceService: this.mountLevelExperienceService,
                talentStoneService: this.talentStoneService,
                characterTrainingService: this.characterTrainingService,
              }
            );
          return this.send(client, result);
        } catch (error: any) {
          this.logger.error(`处理主将训练指令 ${c} 失败:`, error);
          return this.send(client, {
            act_id: c,
            code: -1,
            msg: error?.message || "处理失败",
          });
        }

      // 帮派系统相关指令处理
      case 1236: // 创建帮派
      case 1126: // 帮派信息查询
      case 1218: // 查询帮派成员
      case 1226: // 解散帮派
      case 1197: // 申请加入帮派
      case 1193: // 获取帮派列表
        try {
          if (factionWsHandlers[c]) {
            const result = await factionWsHandlers[c](d, {
              selectedCharacterId: await getSelectedCharacterId(),
              factionService: this.factionService,
              systemMessageService: this.systemMessageService,
              pushMessage: async (message: any) => {
                if (message && message.act_id === 10) {
                  if (!message.info_id || message.info_id === 0) {
                    message.info_id = 1000;
                  }
                }
                this.send(client, message);
              },
            });
            this.send(client, result);
          } else {
            this.send(client, {
              act_id: c,
              code: -1,
              msg: "指令未实现",
            });
          }
        } catch (error: any) {
          this.logger.error(`处理帮派指令 ${c} 失败:`, error);
          this.send(client, {
            act_id: c,
            code: -1,
            msg: error?.message || "处理失败",
          });
        }
        break;

      // 其余逻辑通过 wsHandlers 分发表处理
      default:
        // 所有 code 改由分发表处理，支持两种返回：完整响应或仅 data
        if (Number.isFinite(Number(c)) && wsHandlers[Number(c)]) {
          try {
            const res = await wsHandlers[Number(c)](d, {
              userId: getBoundUserId(),
              selectedCharacterId: await getSelectedCharacterId(),
              getUserToken: async (uid: number) => getUserToken(uid),
              getUserRoles: async (uid: number) => getUserRoles(uid),
              updateSelectedCharacter: async (
                characterId: number,
                roleName: string
              ) => updateSelectedCharacter(characterId, roleName),
              newRoleId: () => this.nextRoleId++,
              characterService: this.characterService,
              redisService: this.redisService,
              chatMessageService: this.chatMessageService,
              privateMessageService: this.privateMessageService,
              announcementService: this.announcementService,
              itemService: this.itemService,
              basicItemService: this.basicItemService,
              inventoryService: this.inventoryService,
              characterMedicineService: this.characterMedicineService,
              characterEquipmentInventoryService:
                this.characterEquipmentInventoryService,
              equipmentBaseService: this.equipmentBaseService,
              monthlyCardService: this.monthlyCardService,
              characterSkillService: this.characterSkillService,
              shopService: this.shopService,
              vipService: this.vipService,
              deputyGeneralService: this.deputyGeneralService,
              bankService: this.bankService,
              casinoService: this.casinoService,
              mapAreaService: this.mapAreaService,
              locationService: this.characterLocationService,
              npcService: this.npcService,
              mountBaseService: this.mountBaseService,
              characterMountService: this.characterMountService,
              mountLevelExperienceService: this.mountLevelExperienceService,
              gemService: this.gemService,
              talentStoneService: this.talentStoneService,
              stallService: (this as any).stallService,
              goldTradeService: this.goldTradeService,
              systemMessageService: this.systemMessageService, // 添加系统消息服务
              playerStatusService: this.playerStatusService,
              houseTrainingService: this.houseTrainingService,
              pushMessage: async (message: any) => {
                if (message && message.act_id === 10) {
                  if (!message.info_id || message.info_id === 0) {
                    message.info_id = 1000;
                  }
                }
                this.send(client, message);
              },
              sendCharacterLocationInfo: async (characterId: number) => {
                await this.sendCharacterLocationInfo(client, characterId);
              },
              pushPrivateMessageNotification: (
                receiverCharacterId: number,
                senderCharacterId: number,
                messageType: number
              ) => {
                this.pushPrivateMessageNotification(
                  receiverCharacterId,
                  senderCharacterId,
                  messageType
                );
              },
              characterAttributeService: this.characterAttributeService,
              characterEquipmentService: this.characterEquipmentService,
              playerOnlineTimeService: this.playerOnlineTimeService,
              deputyAttributeService: this.deputyAttributeService,
            });

            if ([1203].includes(c)) {
              this.sendUserInfo(client, await getSelectedCharacterId());
            }

            if (res && typeof res === "object" && "act_id" in res) {
              return this.send(client, res);
            }
            return this.send(client, {
              act_id: c,
              code: 0,
              msg: "",
              data: res || null,
            });
          } catch (err: any) {
            this.logger.error(`处理WebSocket消息失败，code=${c}:`, err);
            return this.send(client, {
              act_id: c,
              code: -1,
              msg: err?.message || "error",
            });
          }
        }

        if (!Number.isFinite(Number(c)) || !KNOWN_WS_CODES.has(Number(c))) {
          this.logger.warn(`未知的WebSocket指令：${c}`);
        }
        // 尝试 tomb 指令
        if (c === 1591 || c === 1412 || c === 1411 || c === 1592) {
          try {
            const helpers = {
              selectedCharacterId: await getSelectedCharacterId(),
              redisService: this.redisService,
              characterService: this.characterService,
              systemMessageService: this.systemMessageService,
            };
            let res: any;
            if (c === 1591)
              res = await this.tombWsHandlers.handleQueryPits(d, helpers);
            if (c === 1412)
              res = await this.tombWsHandlers.handleBuyShovel(d, helpers);
            if (c === 1411)
              res = await this.tombWsHandlers.handleDig(d, helpers);
            if (c === 1592)
              res = await this.tombWsHandlers.handleHistory(d, helpers);
            if (
              res &&
              (res as any).extra &&
              (res as any).extra.act_id === 1591
            ) {
              this.send(client, res);
              return this.send(client, (res as any).extra);
            }
            return this.send(client, res);
          } catch (err: any) {
            return this.send(client, {
              act_id: c,
              code: -1,
              msg: err?.message || "error",
            });
          }
        }
        return this.send(client, { act_id: c, code: 0, msg: "ok", data: null });

      case 2030: // 使用心法（立即结算）
        try {
          const gid = d?.gid; // 147/148/149/425...
          const cid = d?.cid; // player_deputy.id
          const cnum = d?.c || 1; // 使用数量 1-100
          const selectedCharacterId = meta.selectedCharacterId || 0;
          const res = await this.deputyGeneralService.useDeputyMind(
            selectedCharacterId,
            Number(gid),
            Number(cid),
            Number(cnum)
          );
          const msg = `心法使用成功, 增加经验值 ${res.expGained}${
            res.levelUpTimes > 0 ? ", 升级 " + res.levelUpTimes + " 级" : ""
          }`;
          return this.send(client, { act_id: 2030, code: 0, msg });
        } catch (error: any) {
          return this.send(client, {
            act_id: 2030,
            code: -1,
            msg: error?.message || "使用失败",
          });
        }

      case 2031:
        // 交给通用 handlers（ws-handlers.ts 中已实现 2031 与 2032 一致逻辑）
        try {
          const res = await wsHandlers[2031](d, {
            selectedCharacterId: meta.selectedCharacterId,
            characterService: this.characterService,
            gemService: this.gemService,
          } as any);
          return this.send(client, res);
        } catch (err: any) {
          return this.send(client, {
            act_id: 2031,
            code: -1,
            msg: err?.message || "处理失败",
          });
        }

      case 4438: // 常人心法（立即结算）
        try {
          const gid = d?.gid; // 常人心法道具id（304等）
          const cid = d?.cid; // player_deputy.id
          const cnum = d?.c || 1; // 使用数量 1-100
          const selectedCharacterId = meta.selectedCharacterId || 0;
          const res = await this.deputyGeneralService.useCommonMind(
            selectedCharacterId,
            Number(gid),
            Number(cid),
            Number(cnum)
          );
          const msg = `${res.grade} 级常人心法使用成功, 增加经验值 ${
            res.expGained
          }${res.levelUpTimes > 0 ? ", 升级 " + res.levelUpTimes + " 级" : ""}`;
          return this.send(client, { act_id: 4438, code: 0, msg });
        } catch (error: any) {
          return this.send(client, {
            act_id: 4438,
            code: -1,
            msg: error?.message || "使用失败",
          });
        }

      case 4439: // 常人心法（立即结算）
        try {
          const gid = d?.gid; // 常人心法道具id（304等）
          const cid = d?.cid; // player_deputy.id
          const cnum = d?.c || 1; // 使用数量 1-100
          const selectedCharacterId = meta.selectedCharacterId || 0;
          const res = await this.deputyGeneralService.useCommonMind(
            selectedCharacterId,
            Number(gid),
            Number(cid),
            Number(cnum)
          );
          const msg = `${res.grade} 级常人心法使用成功, 增加经验值 ${
            res.expGained
          }${res.levelUpTimes > 0 ? ", 升级 " + res.levelUpTimes + " 级" : ""}`;
          return this.send(client, { act_id: 4439, code: 0, msg });
        } catch (error: any) {
          return this.send(client, {
            act_id: 4439,
            code: -1,
            msg: error?.message || "使用失败",
          });
        }
    }
  }

  /**
   * 从token中获取用户ID
   * 通过查询数据库中的用户表来验证token
   */
  private async getUserIdFromToken(token: string): Promise<{
    userId: number;
    mobile: string;
    selectedCharacterId?: number;
    characterName?: string;
  } | null> {
    try {
      // 使用UserAuthService从Redis缓存中获取用户信息
      const userData = await this.userAuthService.getUserFromToken(token);
      if (userData) {
        return {
          userId: userData.userId,
          mobile: userData.mobile,
          selectedCharacterId: userData.selectedCharacterId,
          characterName: userData.characterName,
        };
      }

      this.logger.warn(`未找到匹配的token: ${token.substring(0, 8)}...`);
      return null;
    } catch (error: any) {
      this.logger.error("从token获取用户信息失败:", error);
      return null;
    }
  }

  /**
   * 获取用户当前选择的角色ID
   */
  private async getUserSelectedCharacter(
    userId: number
  ): Promise<number | null> {
    try {
      // 首先从Redis缓存中查找
      const cached = await this.redisService.get(
        `user:selected_character:${userId}`
      );
      if (cached) {
        const data = JSON.parse(cached);
        return data.characterId;
      }

      // 如果Redis中没有，从数据库获取用户的第一个可用角色
      const characters = await this.characterService.getUserCharacters(userId);
      if (characters.length > 0) {
        const selectedCharacter =
          characters.find((char) => char.allowLogin === 1) || characters[0];

        // 缓存到Redis
        await this.redisService.set(
          `user:selected_character:${userId}`,
          JSON.stringify({
            characterId: selectedCharacter.id,
            updated_at: Date.now(),
          }),
          86400 // 24小时过期
        );

        return selectedCharacter.id;
      }

      return null;
    } catch (error: any) {
      this.logger.error(`获取用户选择角色失败，userId=${userId}:`, error);
      return null;
    }
  }

  /**
   * 发送位置相关信息
   */
  private async sendLocationInfo(
    client: WebSocket,
    characterId: number,
    character: any
  ): Promise<void> {
    try {
      // 获取玩家当前位置信息
      let currentAreaId = 2; // 默认新手村
      let currentAreaName = "新手村";
      let currentPlayerCount = 0;
      let curAreaInfo: any = null;

      try {
        // 从位置服务获取玩家当前位置
        if (this.characterLocationService) {
          const location =
            await this.characterLocationService.getPlayerLocation(characterId);
          if (location) {
            currentAreaId = location.areaId;
            currentAreaName = location.area?.name || "未知区域";
            curAreaInfo = location.area;
            // 获取当前区域在线玩家数量
            const onlinePlayers =
              await this.characterLocationService.getOnlinePlayersInArea(
                currentAreaId
              );
            currentPlayerCount = onlinePlayers.length;
          }
        }
      } catch (error: any) {
        this.logger.warn(`获取玩家位置信息失败，使用默认值: ${error?.message}`);
      }

      // 1. 发送区域信息 (act_id: 100) 统一由公共服务构建
      const areaInfo = await this.playerStatusService.buildAct100(characterId, {
        characterLocationService: this.characterLocationService,
      });
      this.send(client, areaInfo);

      // 2. 发送NPC列表信息 (act_id: 200)
      try {
        const npcList = await this.npcService.getNpcsByAreaId(currentAreaId);
        const npcListResponse = {
          acc_num: 0,
          act_id: 200,
          npclist: npcList,
        };
        this.send(client, npcListResponse);
      } catch (error) {
        this.logger.warn(
          `获取区域 ${currentAreaId} 的NPC列表失败，使用默认列表: ${
            error instanceof Error ? error.message : String(error)
          }`
        );
        // 如果获取失败，使用默认NPC列表
        const defaultNpcList = {
          acc_num: 0,
          act_id: 200,
          npclist: [],
        };
        this.send(client, defaultNpcList);
      }

      // 4. 发送区域状态信息 (act_id: 120)
      const areaStatus = {
        act_id: 120,
        state: 0,
        txt: "",
      };
      this.send(client, areaStatus);

      this.logger.log(`已发送位置信息：characterId=${characterId}`);
    } catch (error: any) {
      this.logger.error(`发送位置信息失败：${error?.message}`);
    }
  }

  /**
   * 发送历史消息记录 (act_id: 66)
   * 包含聊天消息最近40条和系统消息最近10条
   */
  private async sendHistoryMessages(
    client: WebSocket,
    character: any
  ): Promise<void> {
    try {
      // 获取聊天消息最近40条（包含区域、商业、帮派消息）
      const chatMessages = await this.chatMessageService.getLoginMessages(40);

      // 获取系统消息最近10条
      const systemMessages = await this.chatMessageService.getSystemMessages(
        10
      );

      // 合并所有消息并按时间排序（最新的在前）
      const allMessages = [...systemMessages].sort((a, b) => {
        // 按时间显示格式排序，这里假设格式为 HH:MM
        const timeA = a.h;
        const timeB = b.h;
        return timeB.localeCompare(timeA);
      });

      // 发送历史消息记录 (act_id: 66)
      const historyMessages = {
        act_id: 66,
        code: 0,
        data: allMessages,
      };

      this.send(client, historyMessages);

      this.logger.log(
        `已发送历史消息记录：聊天消息${chatMessages.length}条，系统消息${systemMessages.length}条`
      );
    } catch (error: any) {
      this.logger.error(`发送历史消息记录失败：${error?.message}`);
    }
  }

  /**
   * 发送用户相关信息
   */
  private async sendUserInfo(
    client: WebSocket,
    characterId: number | undefined,
    character?: any
  ): Promise<void> {
    if (!characterId) {
      this.logger.warn(
        `角色ID不存在，无法发送用户信息：characterId=${characterId}`
      );
      return;
    }

    try {
      // 如果没有传入 character 参数，则自动获取角色信息
      let characterData = character;
      if (!characterData) {
        characterData = await this.characterService.getCharacterWithDetails(
          characterId
        );
        if (!characterData) {
          this.logger.warn(
            `角色不存在，无法发送用户信息：characterId=${characterId}`
          );
          return;
        }
      }

      // 使用公共方法获取角色基础属性信息
      const basicAttributes =
        await this.characterAttributeService.getCharacterBasicAttributes(
          characterId
        );

      // 获取角色资源信息
      const resources = characterData.resources || {
        gold: 0,
        silver: 0,
        bdSilver: 0,
        fc: 0,
        superHK: 0,
        tlz: 0,
        tlzs: 0,
        vipBag: 0,
      };

      // 获取真实VIP等级
      let vipLvl = -1;
      try {
        // -2 表示按规则返回当前实际VIP等级
        const vipInfo = await (this as any).vipService?.queryVipInfo(
          characterId,
          -2
        );
        vipLvl = vipInfo?.vipLvl ?? -1;
      } catch (error: any) {
        this.logger.warn(`获取VIP等级失败，使用默认值: ${error?.message}`);
      }

      // 3. 发送角色状态信息 (act_id: 300) 统一由公共服务构建
      const characterStatus = await this.playerStatusService.buildAct300(
        characterId,
        {
          characterService: this.characterService,
          characterAttributeService: this.characterAttributeService,
          vipService: this.vipService,
        }
      );
      this.send(client, characterStatus);

      // 5. 发送背包杂物信息 (act_id: 1425) - 真实的背包数据
      try {
        const miscResult = await this.inventoryService.getCharacterMisc(
          characterId,
          0, // 第0页
          1000 // 获取足够多的物品
        );

        const newbieGift = {
          act_id: 1425,
          code: 0,
          data: miscResult.data,
          page: 1,
          num: miscResult.sum,
        };
        this.send(client, newbieGift);
      } catch (error: any) {
        this.logger.error(`获取背包杂物信息失败：${error?.message}`);
        // 如果查询失败，发送空数据
        const newbieGift = {
          act_id: 1425,
          code: -1,
          msg: error?.message || "获取背包杂物失败",
          data: [],
          page: 1,
          num: 0,
        };
        this.send(client, newbieGift);
      }

      this.logger.log(`已发送用户信息：characterId=${characterId}`);
    } catch (error: any) {
      this.logger.error(`发送用户信息失败：${error?.message}`);
    }
  }

  private async sendMyLoginHomeInfo(
    client: WebSocket,
    characterId: number
  ): Promise<void> {
    try {
      // 获取角色详细信息
      const character = await this.characterService.getCharacterWithDetails(
        characterId
      );
      if (!character) {
        this.logger.warn(
          `角色不存在，无法发送位置信息：characterId=${characterId}`
        );
        return;
      }

      // 发送位置信息
      await this.sendLocationInfo(client, characterId, character);

      // 3. 发送历史消息记录 (act_id: 66)
      // await this.sendHistoryMessages(client, character);

      // 发送用户信息
      await this.sendUserInfo(client, characterId, character);

      // 检查用户是否有未读私信，如果有则推送通知
      await this.checkAndPushUnreadPrivateMessages(characterId, client);

      // 检查用户是否有未读系统消息，如果有则推送通知
      await this.checkAndPushUnreadSystemMessages(characterId, client);

      this.logger.log(`已主动发送角色位置信息：characterId=${characterId}`);
    } catch (error: any) {
      this.logger.error(`发送角色位置信息失败：${error?.message}`);
    }
  }

  /**
   * 主动发送角色位置信息
   */
  private async sendCharacterLocationInfo(
    client: WebSocket,
    characterId: number
  ): Promise<void> {
    const character = await this.characterService.getCharacterWithDetails(
      characterId
    );
    await this.sendLocationInfo(client, characterId, character);
  }

  /**
   * 处理娱乐城中奖通知消息
   */
  private async handleCasinoWinningNotification(
    notification: any
  ): Promise<void> {
    try {
      const { receiverCharacterId, messageContent } = notification;

      // 验证必要参数
      if (!receiverCharacterId) {
        this.logger.error("中奖通知缺少接收者角色ID");
        return;
      }

      // 1. 推送给指定角色的客户端（消息已由CasinoSettlementService保存到数据库）
      this.pushPrivateMessageNotification(receiverCharacterId, 1000, 1); // 1表示系统消息

      this.logger.log(`✅ 中奖通知已推送给角色 ${receiverCharacterId}`);
    } catch (error: any) {
      this.logger.error("处理娱乐城中奖通知消息失败:", error?.message || error);
    }
  }

  // ... existing code ...
}
